package com.qiujie.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qiujie.dto.Response;
import com.qiujie.dto.ResponseDTO;
import com.qiujie.dto.StaffLeaveDTO;
import com.qiujie.entity.*;
import com.qiujie.enums.AppErrorCodeEnum;
import com.qiujie.enums.AuditStatusEnum;
import com.qiujie.enums.ErrorEnum;
import com.qiujie.enums.LeaveEnum;
import com.qiujie.exception.ServiceException;
import com.qiujie.mapper.*;
import com.qiujie.util.EnumUtil;
import com.qiujie.util.HutoolExcelUtil;
import com.qiujie.vo.StaffLeaveVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class StaffLeaveService extends ServiceImpl<StaffLeaveMapper, StaffLeave> {

    @Autowired
    private StaffLeaveMapper staffLeaveMapper;

    @Autowired
    private StaffMapper staffMapper;

    @Autowired
    private DeptMapper deptMapper;

    @Autowired
    private ApproveFlowMapper approveFlowMapper;

    @Autowired
    private ApproveRecordMapper approveRecordMapper;

    @Autowired
    private LeaveMapper leaveMapper;


    public ResponseDTO add(StaffLeave staffLeave) {
        if (save(staffLeave)) {
            return Response.success();
        }
        return Response.error();
    }

    public ResponseDTO delete(Integer id) {
        if (removeById(id)) {
            return Response.success();
        }
        return Response.error();
    }

    @Transactional
    public ResponseDTO deleteBatch(List<Integer> ids) {
        if (removeBatchByIds(ids)) {
            return Response.success();
        }
        return Response.error();
    }

    public ResponseDTO edit(StaffLeave staffLeave) {
        if (updateById(staffLeave)) {
            return Response.success();
        }
        return Response.error();
    }

    public ResponseDTO query(Integer id) {
        StaffLeave staffLeave = getById(id);
        if (staffLeave != null) {
            return Response.success(staffLeave);
        }
        return Response.error();
    }




    // 修改后的列表查询方法
    public ResponseDTO list(Integer current, Integer size, String name, Integer deptId, String code) {
        QueryWrapper<StaffLeave> wrapper = new QueryWrapper<>();

        // 检查字段名称是否与数据库一致
        if (StringUtils.isNotBlank(name)) {
            wrapper.like("name", name);  // 确保数据库字段名为name
        }

        if (deptId != null) {
            wrapper.eq("dept_id", deptId);  // 确保数据库字段名为dept_id
        }

        // 检查code参数逻辑
        if (StringUtils.isNotBlank(code)) {
            wrapper.eq("code", code);  // 确保数据库字段名为code
        }

        Page<StaffLeave> page = new Page<>(current, size);
        return packagePageData(page);
    }













    // 其他原有方法保持不变
    public void export(HttpServletResponse response, String filename) throws IOException {
        List<StaffLeave> list = list();
        HutoolExcelUtil.writeExcel(response, list, filename, StaffLeave.class);
    }



    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO imp(MultipartFile file) throws IOException {
        InputStream inputStream = file.getInputStream();
        List<StaffLeave> list = HutoolExcelUtil.readExcel(inputStream, 1, StaffLeave.class);
        if (saveBatch(list)) {
            return Response.success();
        }
        return Response.error();
    }

    // StaffLeaveService.java 修改方法
    @Transactional(readOnly = true)
    public ResponseDTO queryByStaffId(Integer current, Integer size, Integer staffId) {
        log.info("执行查询：staffId={}, current={}, size={}", staffId, current, size);
        Page<StaffLeave> page = new Page<>(current, size);
        IPage<StaffLeave> result = staffLeaveMapper.listByStaffId(page, staffId);

        // 只返回前端需要的字段
        List<Map<String, Object>> list = result.getRecords().stream().map(staffLeave -> {
            Map<String, Object> map = new HashMap<>();
            map.put("typeNum", staffLeave.getTypeNum());
            map.put("startDate", staffLeave.getStartDate());
            map.put("days", staffLeave.getDays());
            map.put("status", staffLeave.getStatus().getCode());
            map.put("remark", staffLeave.getRemark());
            return map;
        }).collect(Collectors.toList());

        Map<String, Object> data = new HashMap<>();
        data.put("pages", result.getPages());
        data.put("total", result.getTotal());
        data.put("list", list);

        return Response.success(data);
    }




    public ResponseDTO queryAll() {
        List<Map<String, Object>> enumList = EnumUtil.getEnumList(AuditStatusEnum.class);
        for (Map<String, Object> map : enumList) {
            for (AuditStatusEnum status : AuditStatusEnum.values()) {
                if (map.get("code") == status.getCode()) {
                    map.put("tagType", status.getTagType());
                }
            }
        }
        return Response.success(enumList);
    }



    // 核心改造部分开始
    public ResponseDTO apply(StaffLeave staffLeave) {

        // 1. 基础校验
        if (staffLeave.getDays() == null || staffLeave.getDays() <= 0) {
            return ErrorEnum.PARAM_TYPE.toResponse("请假天数必须为正整数");
        }

        // 2. 获取员工信息
        Staff staff = staffMapper.selectById(staffLeave.getStaffId());
        if (staff == null) {
            return ErrorEnum.STAFF_CODE.toResponse();
        }

        // 3. 查询有效配置
        Leave config = leaveMapper.selectOne(new QueryWrapper<Leave>()
                .eq("dept_id", staff.getDeptId())
                .eq("type_num", staffLeave.getTypeNum().getCode())
                .eq("status", 1));

        if (config == null) {
            return ErrorEnum.LEAVE_TYPE.toResponse("未找到有效配置");
        }

        // 4. 保存记录
        staffLeave.setStatus(AuditStatusEnum.UNAUDITED);
        staffLeave.setFlowType(determineFlowType(staff));
        return save(staffLeave) ? Response.success() : Response.error();
    }






















    @Transactional
    public ResponseDTO approve(Integer leaveId, Integer status, String remark, String approverCode) {
        // 1. 验证审批人身份
        Staff approver = staffMapper.selectOne(new QueryWrapper<Staff>().eq("code", approverCode));
        if (approver == null) {
            throw new ServiceException(AppErrorCodeEnum.APPROVER_NOT_FOUND);
        }

        // 2. 获取请假申请详情
        StaffLeave leave = getById(leaveId);
        if (leave == null) {
            throw new ServiceException(AppErrorCodeEnum.APPLICATION_NOT_FOUND);
        }

        // 3. 创建审批记录
        createApproveRecord(leaveId, leave.getCurrentNode(), status, remark, approver.getId());

        // 4. 处理审批结果
        if (status.equals(AuditStatusEnum.APPROVE.getCode())) {
            return processApproval(leave);
        } else {
            return processRejection(leave);
        }
    }

    // 修改processApproval方法中的循环逻辑
    private ResponseDTO processApproval(StaffLeave leave) {
        List<ApproveFlow> flows = approveFlowMapper.getByFlowKey(leave.getFlowType());

        while (true) {
            // 获取下一个审批节点（currentNode+1）
            ApproveFlow nextNode = flows.stream()
                    .filter(f -> f.getNodeOrder() > leave.getCurrentNode())
                    .findFirst()
                    .orElse(null);

            // 最终审批完成
            if (nextNode == null) {
                leave.setStatus(AuditStatusEnum.APPROVE);
                leave.setCurrentNode(flows.size() + 1);
                updateById(leave);
                return Response.success("审批流程完成");
            }

            // 查找当前节点审批人
            List<Staff> approvers = findApprovers(nextNode.getRoleCode(), leave.getStaffId());

            // 处理自动跳过逻辑
            if (approvers.isEmpty() && Boolean.TRUE.equals(nextNode.getAutoSkip())) {
                leave.setCurrentNode(nextNode.getNodeOrder());
                updateById(leave);
                continue;
            }

            // 创建待审批记录
            ApproveRecord pendingRecord = new ApproveRecord();
            pendingRecord.setLeaveId(leave.getId());
            pendingRecord.setNodeOrder(nextNode.getNodeOrder());
            pendingRecord.setApproverRole(nextNode.getRoleCode());
            pendingRecord.setStatus(AuditStatusEnum.AUDITING.getCode());
            approveRecordMapper.insert(pendingRecord);

            // 更新申请状态
            leave.setCurrentNode(nextNode.getNodeOrder());
            leave.setStatus(AuditStatusEnum.AUDITING);
            updateById(leave);

            return Response.success("等待【" + nextNode.getRoleCode() + "】审批");
        }
    }


    // 审批人查找逻辑
    private List<Staff> findApprovers(String roleCode, Integer staffId) {
        Staff applicant = staffMapper.selectById(staffId);
        Dept dept = deptMapper.selectById(applicant.getDeptId());

        // 矿领导部门特殊处理
        if ("矿领导".equals(dept.getName())) {
            return staffMapper.findByRoles(Arrays.asList("kz", "dwsj"))
                    .stream()
                    .filter(s -> s.getStatus() == 1)
                    .collect(Collectors.toList());
        }

        // 原有审批逻辑
        switch (roleCode) {
            case "bmfzr":
                return findDeptLeaders(dept);
            case "kqz":
                return staffMapper.findByRoleAndDept("kqz", dept.getId());
            case "rlzyb":
                return staffMapper.findByRole("rlzyb");
            case "fgkld":
                return findMineLeaders("fgkld");
            case "fgrlkld":
                return findMineLeaders("fgrlkld");
            case "kz":
            case "dwsj":
                return staffMapper.findByRoles(Arrays.asList("kz", "dwsj"));
            default:
                return staffMapper.findByRole(roleCode);
        }
    }

    // 查找部门负责人（包含正副职）
    private List<Staff> findDeptLeaders(Dept dept) {
        List<Staff> leaders = new ArrayList<>();

        // 根据部门类型匹配角色
        if (dept.isTeamDept()) {
            leaders.addAll(staffMapper.findByRoleAndDept("dz", dept.getId()));  // 队长
            leaders.addAll(staffMapper.findByRoleAndDept("fdz", dept.getId())); // 副队长
        } else if (dept.isNormalDept()) {
            leaders.addAll(staffMapper.findByRoleAndDept("bz", dept.getId()));  // 部长
            leaders.addAll(staffMapper.findByRoleAndDept("fbz", dept.getId())); // 副部长
        }

        return leaders.stream()
                .filter(s -> s.getStatus().equals(1))
                .collect(Collectors.toList());
    }
    // 查找矿领导部门成员
    private List<Staff> findMineLeaders(String roleCode) {
        // 角色代码校验
        if (!roleCode.startsWith("fg")) {
            throw new ServiceException(AppErrorCodeEnum.SPECIAL_ROLE_LIMIT.getCode(),
                    "非分管领导角色：" + roleCode);
        }

        // 查询矿领导部门
        Dept mineDept = deptMapper.selectOne(
                new QueryWrapper<Dept>().eq("name", "矿领导"));

        if (mineDept == null) {
            log.error("系统配置错误：矿领导部门不存在");
            throw new ServiceException(AppErrorCodeEnum.MINE_DEPT_NOT_FOUND);
        }

        // 获取分管领导
        List<Staff> leaders = staffMapper.findByRoleAndDept(roleCode, mineDept.getId());

        if (leaders.isEmpty()) {
            throw new ServiceException(AppErrorCodeEnum.APPROVER_NOT_FOUND.getCode(),
                    roleCode + "角色审批人未配置");
        }

        return leaders.stream()
                .filter(s -> s.getStatus() == 1)
                .collect(Collectors.toList());
    }



    private String determineFlowType(Staff staff) {
        try {
            // 1. 优先判断矿领导部门
            Dept dept = deptMapper.selectById(staff.getDeptId());
            if (dept == null) {
                throw new ServiceException(AppErrorCodeEnum.DEPT_NOT_FOUND);
            }

            if ("矿领导".equals(dept.getName())) {
                return "mine_leader_flow";
            }

            // 2. 根据角色判断流程类型
            Set<String> roles = staffMapper.getRolesByStaffId(staff.getId());
            if (roles == null || roles.isEmpty()) {
                throw new ServiceException(AppErrorCodeEnum.ROLE_NOT_FOUND);
            }

            if (roles.contains("bz") || roles.contains("zbsj") || roles.contains("dz")) {
                return "leader_flow";
            }

            if (roles.contains("zgjsy") || roles.contains("fdz")
                    || roles.contains("fbz") || roles.contains("fzrs")) {
                return "middle_flow";
            }

            // 3. 部门级别兜底判断
            String leaderLevel = approveFlowMapper.getRoleLevelByCode(dept.getLeaderRole());
            if (leaderLevel == null) {
                throw new ServiceException(AppErrorCodeEnum.APPROVAL_FLOW_ERROR.getCode(),
                        "角色级别配置缺失");
            }

            return switch (leaderLevel) {
                case "高级" -> "leader_flow";
                case "中级" -> "middle_flow";
                default -> "common_flow";
            };
        } catch (Exception e) {
            throw new ServiceException(AppErrorCodeEnum.APPROVAL_FLOW_ERROR.getCode(),
                    "流程判断异常：" + e.getMessage());
        }
    }



    // 辅助方法保持不动
    private ResponseDTO packagePageData(IPage<?> page) {
        Map<String, Object> map = new HashMap<>();
        map.put("pages", page.getPages());
        map.put("total", page.getTotal());
        map.put("list", page.getRecords());
        return Response.success(map);
    }



    // 驳回处理
    private ResponseDTO processRejection(StaffLeave leave) {
        leave.setStatus(AuditStatusEnum.REJECT);
        leave.setCurrentNode(-1); // 标记为已驳回
        if (updateById(leave)) {
            return Response.success("申请已驳回");
        }
        return Response.error("驳回操作失败");
    }


    @Transactional(readOnly = true)
    public ResponseDTO listPendingApprovals(Integer current, Integer size, String currentUserCode) {
        // 获取当前用户角色
        Staff currentUser = staffMapper.selectOne(
                new QueryWrapper<Staff>().eq("code", currentUserCode)
        );
        Set<String> roles = staffMapper.getRolesByStaffId(currentUser.getId());

        // 分页查询
        IPage<StaffLeaveVO> page = staffLeaveMapper.selectPendingList(
                new Page<>(current, size),
                roles,
                AuditStatusEnum.AUDITING.getCode()
        );

        // 补充审批记录
        page.getRecords().forEach(leave ->
                leave.setApproveRecords(approveRecordMapper.selectList(
                        new QueryWrapper<ApproveRecord>()
                                .eq("leave_id", leave.getId())
                ))
        );

        return Response.success(page);


    }

    /**
     * 创建审批记录
     */
    @Transactional
    public void createApproveRecord (Integer leaveId, Integer nodeOrder,
                                      Integer status, String remark, Integer approverId){
        Staff approver = staffMapper.selectById(approverId);
        ApproveRecord record = new ApproveRecord();
        record.setLeaveId(leaveId);
        record.setNodeOrder(nodeOrder);
        record.setApproverId(approverId);
        record.setApproverName(approver.getName());
        record.setStatus(status);
        record.setRemark(remark);
        approveRecordMapper.insert(record);
    }




}
